Skip to content

test: migrate AVA→Vitest with event-based waits (stacked on #131)#132

Draft
zeevmoney wants to merge 6 commits into
per-15306/ci-pin-actions-tests-on-prfrom
per-15315/vitest-event-based-tests
Draft

test: migrate AVA→Vitest with event-based waits (stacked on #131)#132
zeevmoney wants to merge 6 commits into
per-15306/ci-pin-actions-tests-on-prfrom
per-15315/vitest-event-based-tests

Conversation

@zeevmoney

Copy link
Copy Markdown
Contributor
  • What kind of change does this PR introduce?

    Test infrastructure modernization. PR#2 of a 3-PR stack — stacked on ci: pin actions to SHA and run full test suite on PRs #131 (base branch per-15306/ci-pin-actions-tests-on-pr, not main). No shipped SDK source changes. Linear: PER-15315.

  • What is the current behavior?

    • Tests run on AVA 3, compiled via tsup to build/** then run from the built JS.
    • e2e tests wait for cloud→PDP propagation with hardcoded sleep(10s) / setTimeout, which is slow and flaky once they run in CI.
    • Two specs (bulk_test.spec.ts, e2e/lists.e2e.spec.ts) are orphaned — run by no script.
  • What is the new behavior?

    • AVA → Vitest 4.1. One vitest.config.ts with four projects: unit (parallel), module-imports, integration (serial), e2e (serial). Backend projects run single-fork / maxWorkers:1 and as separate vitest invocations so they never collide on the shared env. test:ci:unit / test:ci:full script names are unchanged, so PR#1's ci.yaml needs no edit.
    • No timer-based waits. A new waitFor / waitForCheck helper polls the actual permit.check() until it converges (bounded timeout) — replacing every sleep. The rebac gate now waits until all step assertions converge (positives true and negatives false); lists waits until the bulk-created users are listable before asserting counts.
    • Quality pass on every spec. fixtures.ts is now a createTestClient() factory; handleApiError throws (fail-fast); try/catch(t.fail)/finallytry/finally; all t.*expect. Every e2e spec now fully and tolerantly cleans up what it creates in afterAll, so the serial suite is order-independent.
    • Orphaned specs wired in. bulk_test.spec.tse2e/bulk.e2e.spec.ts (self-contained schema + full cleanup; preserves the only bulkRelationshipTuples coverage). lists.e2e.spec.ts is prefix-scoped + cleaned up (no more absolute-count coupling).
    • Module-import specs load the built bundle (build/index.{js,mjs}) to keep packaging/entry-point regression coverage; those scripts retain a build prerequisite.
    • Deps: drop ava, @ava/typescript, nyc, @istanbuljs/nyc-config-typescript, codecov, ts-node, open-cli; add vitest@^4.1, @vitest/coverage-v8@^4.1; @types/node@^20; skipLibCheck for Vitest's d.ts.
  • Other information:

    How it was tested

    • yarn test:ci:unit (the no-backend gate: unit + module-imports) — 60 tests pass. yarn build + tsc clean, yarn lint clean.
    • Integration + e2e specs compile and are discovered by Vitest; they require a live Permit env + PDP and are exercised by the test:ci:full path in CI (this PR's CI run validates them end-to-end). They could not be run on a live backend locally.
    • New deterministic unit/wait-for-sync.spec.ts pins the waitForSync header contract (X-Wait-Timeout / X-Timeout-Policy, PDP basePath, no-op without proxyFactsViaPdp) with no network.

    Notable decisions

    • local_facts "Check skip wait" asserted a result before propagation — inherently racy. It's now it.skip with an explanatory comment, and its contract is covered deterministically by the new unit test.
    • The 100% nyc coverage gate (never enforced in CI) is dropped; @vitest/coverage-v8 is available via yarn coverage, scoped to the unit-covered modules.

    Known limitation

    • e2e behavior against a live PDP is validated by CI on this PR, not locally. If the first CI run reveals timing/propagation tuning needs (poll budgets, lists search-match semantics), expect a small follow-up commit.

    Deferred to PR#3 (coverage expansion)

    • Strengthening the "does-not-throw"-only bulk assertions and the access-level early-returns; broader unit coverage of the waitForSync edge branches.

Generated with Claude Code

Replace AVA 3 with Vitest 4.1 (vitest.config.ts with unit / module-imports
/ integration / e2e projects; backend projects run serially via forks +
maxWorkers=1 to avoid shared-env collisions). Keep test:ci:unit /
test:ci:full names so the CI workflow is unchanged.

Remove every timer-based propagation wait: a new waitFor/waitForCheck
helper polls the actual permit.check() until it converges, bounded by a
timeout, replacing the fixed sleep(10s) waits in the e2e suites.

Rewrite fixtures to a createTestClient() factory (handleApiError now
throws). Migrate all t.* assertions to expect. Module-import specs load
the built bundle (build/index.{js,mjs}) to keep packaging-regression
coverage. Wire in the two previously orphaned specs (bulk, lists) with
proper setup/cleanup; preserve bulkRelationshipTuples coverage. Keep the
inherently racy local_facts "skip wait" case as it.skip and add a
deterministic waitForSync header unit test. Drop ava/nyc/codecov/ts-node;
add vitest/@vitest/coverage-v8; bump @types/node to ^20; skipLibCheck for
Vitest's d.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jun 28, 2026

Copy link
Copy Markdown

PER-15315

zeevmoney and others added 5 commits June 28, 2026 23:42
…test-event-based-tests

* per-15306/ci-pin-actions-tests-on-pr:
  ci: run unit/integration/module-imports on PR, defer e2e to next PR

# Conflicts:
#	package.json
…test-event-based-tests

* per-15306/ci-pin-actions-tests-on-pr:
  ci: run on all pull requests, not only those targeting main
…test-event-based-tests

* per-15306/ci-pin-actions-tests-on-pr:
  ci: pin PDP connection to IPv4 (127.0.0.1) in the backend test run
The dockerized PDP in CI doesn't expose OPA (port 8181), so rbac's direct
useOpa checks hit ECONNREFUSED. Gate them behind PERMIT_RUN_OPA_E2E
(default off) so they only run against an OPA-exposed setup. Raise the
rebac convergence gate to 150s and the e2e test timeout to 300s, since
the heavy ReBAC graph needs longer to propagate cloud->PDP on a cold env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bulkCheck and getUserPermissions query separate PDP endpoints that can
lag a single permit.check, so the direct assertions raced cloud->PDP
propagation and flaked on the slower matrix leg. Gate the complete-user
read and poll bulkCheck/getUserPermissions until they converge before
asserting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant